//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#include "InhibitorsBioAssayKd.h"

#include <iostream>
#include <fstream>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <math.h>

#include <zlib.h>
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#define LENGTHLINE  50000
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
using namespace std;
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
InhibitorsBioAssayKd::InhibitorsBioAssayKd() {

  this->namefileListInhibitors = new String();
  this->namefileListProteins   = new String();
  this->namefileMatrix         = new String();
  this->namefileResult         = new String();

  this->inhibitorsList         = new TListE <String> ();
  this->proteinsList           = new TListE <String> ();

  this->matrixValue            = NULL;
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
InhibitorsBioAssayKd::InhibitorsBioAssayKd(String* namefileListInhibitors, String* namefileListProteins, String* namefileResult) {
    
  this->namefileListInhibitors = new String(namefileListInhibitors);
  this->namefileListProteins   = new String(namefileListProteins);
  this->namefileMatrix         = new String(namefileMatrix);
  this->namefileResult         = new String(namefileResult);

  this->inhibitorsList         = new TListE <String> ();
  this->proteinsList           = new TListE <String> ();

  this->matrixValue            = NULL;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
InhibitorsBioAssayKd::~InhibitorsBioAssayKd() {

  if (this->matrixValue) {
    for (int i = 0; i < this->inhibitorsList->Length(); i++)
      if (this->matrixValue[i]) delete[] this->matrixValue[i];
    delete[] this->matrixValue;
  }

  if (this->namefileListInhibitors) delete this->namefileListInhibitors;
  if (this->namefileListProteins)   delete this->namefileListProteins;
  if (this->namefileResult)         delete this->namefileResult;
  if (this->namefileMatrix)         delete this->namefileMatrix;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void InhibitorsBioAssayKd::NamefileListInhibitors(String* namefileListInhibitors) {
  if (!namefileListInhibitors) return;
  *(this->namefileListInhibitors) = *namefileListInhibitors;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void InhibitorsBioAssayKd::NamefileListProteins(String* namefileListProteins) {
  if (!namefileListProteins) return;
  *(this->namefileListProteins) = *namefileListProteins;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void InhibitorsBioAssayKd::NamefileMatrix(String* namefileMatrix) {
  if (!namefileMatrix) return;
  *(this->namefileMatrix) = *namefileMatrix;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void InhibitorsBioAssayKd::NamefileResult(String* namefileResult) {
  if (!namefileResult) return;
  *(this->namefileResult) = *namefileResult;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void InhibitorsBioAssayKd::InhibitorsList(TListE <String>* inhibitorsList) {
  *(this->inhibitorsList) = *inhibitorsList;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void InhibitorsBioAssayKd::ProteinsList(TListE <String>* proteinsList) {
  *(this->proteinsList) = *proteinsList;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void InhibitorsBioAssayKd::MatrixValue(double** matrixValue) {
  
  if (!this->inhibitorsList || !this->proteinsList || !this->inhibitorsList->Length() || !this->proteinsList->Length()) return;

  this->matrixValue = new double*[this->inhibitorsList->Length()];
  for (int i = 0; i < this->inhibitorsList->Length(); i++) {
    if (!matrixValue[i]) { this->matrixValue[i] = NULL; continue; }
    this->matrixValue[i] = new double[this->proteinsList->Length()];
    for (int j = 0; j < this->proteinsList->Length(); j++)
      if (matrixValue[i][j]) this->matrixValue[i][j] = matrixValue[i][j];
  }

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* InhibitorsBioAssayKd::NamefileListInhibitors(void) {
  return this->namefileListInhibitors;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* InhibitorsBioAssayKd::NamefileListProteins(void) {
  return this->namefileListProteins;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* InhibitorsBioAssayKd::NamefileMatrix(void) {
  return this->namefileMatrix;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* InhibitorsBioAssayKd::NamefileResult(void) {
  return this->namefileResult;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
TListE <String>* InhibitorsBioAssayKd::InhibitorsList(void) {
  return this->inhibitorsList;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
TListE <String>* InhibitorsBioAssayKd::ProteinsList(void) {
  return this->proteinsList;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
double** InhibitorsBioAssayKd::MatrixValue(void) {
  return this->matrixValue;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool InhibitorsBioAssayKd::LoadListFile() {

  if (!this->namefileListInhibitors || !this->namefileListProteins->Length() ||
      !this->namefileListProteins   || !this->namefileListInhibitors->Length())
    return false;

  char   buffer[LENGTHLINE + 1];

  gzFile fileInhibitors = gzopen(this->namefileListInhibitors->Out(), "rb9");
  while (!gzeof(fileInhibitors)) {
    gzgets(fileInhibitors, buffer, LENGTHLINE);
    String* element = new String(buffer);
    element->Trim();
    if (element->Length()) this->inhibitorsList->Add(element);
    else                   delete element;
  }
  gzclose(fileInhibitors);

  gzFile fileProteins = gzopen(this->namefileListProteins->Out(), "rb9");
  while (!gzeof(fileProteins)) {
    gzgets(fileProteins, buffer, LENGTHLINE);
    String* element = new String(buffer);
    element->Trim();
    if (element->Length()) this->proteinsList->Add(element);
    else                   delete element;
  }
  gzclose(fileProteins);

  return true;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool InhibitorsBioAssayKd::LoadListFile(String* namefileListInhibitors, String* namefileListProteins) {
    
  this->NamefileListInhibitors(namefileListInhibitors);
  this->NamefileListProteins(namefileListProteins);
  
  if (!this->LoadListFile()) return false;
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool InhibitorsBioAssayKd::LoadMatrix() {

  if (!this->AllocateMatrixValue() || !this->namefileMatrix || !this->namefileMatrix->Length())
    return false;

  char              buffer[LENGTHLINE + 1];
  int               row       = 0;
  bool              headerRow = true;
  
  TListE <String>*  column    = new TListE <String> ();

  gzFile fileMatrix = gzopen(this->namefileMatrix->Out(), "rb9");

  while (!gzeof(fileMatrix)) {

    gzgets(fileMatrix, buffer, LENGTHLINE);
    if (headerRow) { headerRow = false; continue; }

    column->Clear();
    this->SplitColumn(buffer, column, " ");

    if (row < this->proteinsList->Length()) {
      for (int i = 1; i < column->Length(); i++)
        matrixValue[i-1][row] = atof(column->Get(i)->Out());
    }
    row++;
    
  }

  gzclose(fileMatrix);

  if (column) delete column;

  return true;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool InhibitorsBioAssayKd::ComputeNormalizedKdEuclidianDistance() {

  if (!this->matrixValue || !this->namefileResult || !this->namefileResult->Length())
    return false;

  double** matrixResult = new double*[this->inhibitorsList->Length()];
  for (int i = 0; i < this->inhibitorsList->Length(); i++) {
    matrixResult[i] = new double[this->inhibitorsList->Length()];
    for (int j = 0; j < this->inhibitorsList->Length(); j++)
      matrixResult[i][j] = 0;
  }

  double higherValue = 0;

  for (int i = 0; i < this->inhibitorsList->Length(); i++) 
    for (int j = i + 1; j < this->inhibitorsList->Length(); j++) {
      double kDij = 0;
      for (int k = 0; k < this->proteinsList->Length(); k++)
        kDij += pow((this->matrixValue[i][k] - this->matrixValue[j][k]), 2);
      kDij = (double)sqrt(kDij)/(double)this->proteinsList->Length();
      matrixResult[i][j] = matrixResult[j][i] = kDij;
      higherValue = (kDij > higherValue)?kDij:higherValue;
    }

  fstream fileResult;

  fileResult.open(this->namefileResult->Out(), fstream::out);

  if (fileResult.is_open()) {

    for (int i = 0; i < this->inhibitorsList->Length(); i++) {
      fileResult.width(25);
      fileResult.left;
      fileResult << this->inhibitorsList->Get(i)->Out() << " ";
    }
    fileResult << endl;
      
    for (int i = 0; i < this->inhibitorsList->Length(); i++) {
      for (int j = 0; j < this->inhibitorsList->Length(); j++) {
        matrixResult[i][j] /= higherValue;
        matrixResult[i][j]  = 1 - matrixResult[i][j];
        fileResult.width(25);
        fileResult.left;
        fileResult << matrixResult[i][j] << " ";
      }
      fileResult << endl;
    }

    fileResult.close();

  }
  else return false;

  return true;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool InhibitorsBioAssayKd::ComputeKdEuclidianDistance() {

  if (!this->matrixValue || !this->namefileResult || !this->namefileResult->Length())
    return false;

  double** matrixResult = new double*[this->inhibitorsList->Length()];
  for (int i = 0; i < this->inhibitorsList->Length(); i++) {
    matrixResult[i] = new double[this->inhibitorsList->Length()];
    for (int j = 0; j < this->inhibitorsList->Length(); j++)
      matrixResult[i][j] = 0;
  }

  for (int i = 0; i < this->inhibitorsList->Length(); i++)
    for (int j = i + 1; j < this->inhibitorsList->Length(); j++) {
      double kDij = 0;
      for (int k = 0; k < this->proteinsList->Length(); k++)
        kDij += pow((this->matrixValue[i][k] - this->matrixValue[j][k]), 2);
      kDij = (double)sqrt(kDij)/(double)this->proteinsList->Length();
      matrixResult[i][j] = matrixResult[j][i] = kDij;
    }

  fstream fileResult;

  fileResult.open(this->namefileResult->Out(), fstream::out);

  if (fileResult.is_open()) {

    for (int i = 0; i < this->inhibitorsList->Length(); i++) {
      fileResult.width(25);
      fileResult.left;
      fileResult << this->inhibitorsList->Get(i)->Out() << " ";
    }
    fileResult << endl;

    for (int i = 0; i < this->inhibitorsList->Length(); i++) {
      for (int j = 0; j < this->inhibitorsList->Length(); j++) {
        fileResult.width(25);
        fileResult.left;
        fileResult << matrixResult[i][j] << " ";
      }
      fileResult << endl;
    }

    fileResult.close();

  }
  else return false;

  return true;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool InhibitorsBioAssayKd::ClearMatrixValue() {
  if (this->matrixValue) {
    for (int i = 0; i < this->inhibitorsList->Length(); i++)
      if (this->matrixValue[i]) delete[] this->matrixValue[i];
    delete[] this->matrixValue;
  }
  this->matrixValue = NULL;
  return true;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool InhibitorsBioAssayKd::AllocateMatrixValue() {
    
  if (!this->inhibitorsList || !this->inhibitorsList->Length() ||
      !this->proteinsList   || !this->proteinsList->Length())
    return false;

  this->ClearMatrixValue();

  this->matrixValue = new double*[this->inhibitorsList->Length()];
  for (int i = 0; i < this->inhibitorsList->Length(); i++) {
    this->matrixValue[i] = new double[this->proteinsList->Length()];
    for (int j = 0; j < this->proteinsList->Length(); j++)
      this->matrixValue[i][j] = 0;
  }

  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool InhibitorsBioAssayKd::SplitColumn(char* buffer, TListE<String>* columns, const char* characters) {

  if (!buffer || !columns || !characters) return false;

  char *part = strtok(buffer, characters);

  while (part) {
    String* cell = new String(part);
    cell->Trim();
    columns->Add(cell);
    part = strtok(NULL, characters);
  }

  return true;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
